package com.wonders.bigdata.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * Description: <br>
 *
 * @author: XB
 * @date: 2021/5/10 10:55
 */
public class NIOserver {
    public static void main(String[] args) throws Exception {
        // 创建serverSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 得到一个selector对象
        Selector selector = Selector.open();

        // 绑定一个端口6666， 在服务器端监听客户端连接
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));
        // 设置为非阻塞
        serverSocketChannel.configureBlocking(false);

        // 把serverSocketChannel注册到selector关心事件为OP_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 循环等待客户端连接
        while (true) {
            // 这里等待1s，如果没有事件发生，返回
            if (selector.select(1000) == 0) {
                System.out.println("服务器等待了1秒，无连接");
                continue;
            }

            // 如果返回的>0，就获取到相关的selectionKey集合
            // 1.如果返回的>0，表示已经获取到关注的事件
            // 2.selector.selectedKeys() 返回相关的集合
            // 通过selectionKeys 反向获取通道
            Set<SelectionKey> selectionKeys = selector.selectedKeys();

            // 遍历selectionKeys集合，使用迭代器遍历
            Iterator<SelectionKey> iterator =  selectionKeys.iterator();
            while (iterator.hasNext()) {
                // 获取到SelectionKey
                SelectionKey next = iterator.next();
                // 根据key判断事件类型,如果是OP_ACCEPT，则表示有新的客户端连接
                if (next.isAcceptable()) {
                    // 该客户端生成一个SocketChannel，负责进行读写操作
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    System.out.println("客服端连接唱歌，生成一个socketChannel " + socketChannel.hashCode());
                    // 将socketChannel设置为非阻塞
                    socketChannel.configureBlocking(false);
                    // 将socketChannel注册到selector中,关注事件为OP_READ，同时给socketChannel关联一个buffer
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));

                }
                // 如果是OP_READ
                if (next.isReadable()) {
                    // 通过next反向获取channel
                    SocketChannel channel = (SocketChannel)next.channel();
                    // 获取该channel中的buffer
                    ByteBuffer byteBuffer = (ByteBuffer)next.attachment();
                    channel.read(byteBuffer);
                    System.out.println("from客户端：" + new String(byteBuffer.array()));
                }

                // 手动从集合中移动当前的selectionKey，防止重复操作
                iterator.remove();
            }

        }
    }
}
